/***************************************************************************
 *   Copyright (c) YEAR YOUR NAME         <Your e-mail address>            *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/


#include "PreCompiled.h"
#ifndef _PreComp_
#endif

#include <ctime>
//#include <Gui/SoFCUnifiedSelection.h>

#include <QtCore/QObject>
//#include <QtCore/QThread>
//#include <qtcore/QString>
#include <QtCore/QTimer>
#include <QtCore/QEventLoop>
#include <QtCore/QCoreApplication>

//#include <QtGui/QPushButton>
#include <QWidgetList>
#include <QtGui/QMainWindow>
#include <QtGui/QDockWidget>
#include <Qtgui/QMessageBox>

#include "FrameReader.h"
#include "GraphTools.h"
#include "FrameMaker.h"
#include "ddapostplayer.h"
#include "DFCalculator.h"
#include <stdio.h>
#include <errno.h>

#ifdef WIN32
#include <winbase.h>
#endif

#include <Inventor/Qt/viewers/SoQtViewer.h>

#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <App/Document.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/Control.h>

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

namespace DDAGui{
	bool DEBUG = true;
	extern char currentProjectPath[300];

    void sleep( double seconds )
    {
        QTimer t;
        QEventLoop eventloop;
        QObject::connect(&t , SIGNAL(timeout()) , &eventloop , SLOT(quit()));
        t.setSingleShot(true);
        t.start(seconds*10); // make a pause of 20 s
        eventloop.exec(); // stops here until the timeout() signal is emitted
    }

    void showErrorMessageBox(const string& title , const string& text )
    {
        QMessageBox msgBox( QMessageBox::Critical, QString::fromStdString(title)
                , QString::fromStdString(text) );
        msgBox.exec();
    }

	void msg2File(const char* str)
	{
		//return;
		char file[300];
		sprintf(file, "%s/df_debug_log.txt",currentProjectPath);
		FILE* fp= fopen(file, "ab");
		if(!fp)
			FILE* fp= fopen(file, "wb");

		fprintf( fp ,str);
		fclose(fp);
	}

	void msg(const char* str)
	{
		if (DEBUG)
		{
			Base::Console().Message(str);
			//msg2File(str);
		}
	}

    void msgString(const string& str)
    {
		return;
		char file[300];
		sprintf(file, "%s/df_debug_log.txt",currentProjectPath);
		FILE* fp= fopen(file, "ab");
		if(!fp)
			FILE* fp= fopen(file, "wb");

        fwrite(str.c_str() , sizeof(char) , str.size() , fp);
        fclose(fp);
    }

	void msgQString(QString str)
	{
		if(DEBUG)
			msg(str.toStdString().c_str());
	}
	void saveTime()
	{
		char currentTime[200];
		time_t rawtime;
		struct tm * timeinfo;

		time ( &rawtime );
		timeinfo = localtime ( &rawtime );
		sprintf ( currentTime , "\n\n**************************************\n*********   %s**************************************\n", asctime (timeinfo) );
		msg2File(currentTime);
	}

    void viewFitAll()
    {
//        Gui::Application::Instance->runCommand(false , "Std_ViewFitAll");
        Base::Interpreter().runString("FreeCADGui.runCommand(\'Std_ViewFitAll\')");
        Base::Interpreter().runString("Gui.SendMsgToActiveView(\"ViewFit\")");
    }

}
using namespace DDAGui;


int sum = 0;

void testFrameReader()
{
	FrameReader reader;
	reader.setFile("D:/DDAProject/data.dg");
 	std::vector<int> schema = reader.getSchema();
	std::vector<double> windowInfo = reader.getWindowInfo();
 	char str[200];
 	sprintf(str , "%d %d %d %d %d %d %d\n%lf %lf %lf %lf\n" , int(schema[0]) , int(schema[1]) , int(schema[2])
 		, int(schema[3]) , int(schema[4]) , int(schema[5]) , int(schema[6]) 
 		, windowInfo[0] , windowInfo[1] , windowInfo[2] , windowInfo[3]);
 	msg(str);
	string tmpStr = reader.getNextFrame();
	while(tmpStr.size()>0){ /*msgQString(tmpStr);*/ tmpStr = reader.getNextFrame();}
}

void testFrameDataTaker()
{
	FrameDataTaker dataTaker;
    bool flag = dataTaker.setFile("D:/DDAProject/data.dg");
	assert(flag);
	FrameData graph = dataTaker.getNextGraph();
}


SoSeparator* getFreeCADRootNode()
{
    Gui::Document* doc = Gui::Application::Instance->getDocument("DDA");
    assert(doc);
    Gui::View3DInventor* view = dynamic_cast<Gui::View3DInventor*>(doc->getActiveView());
    assert(view);
    if (view) {
        Gui::View3DInventorViewer* viewer = view->getViewer();
        SoNode* rootNode =  viewer->getSceneGraph();
        SoSeparator* node = static_cast<SoSeparator*>(rootNode);
        assert(node);
        msg("root scene graph node got.\n");
        return node;
    }
}

QWidget* getRootWidget()
{
    Gui::Document* doc = Gui::Application::Instance->getDocument("DDA");
    assert(doc);
    Gui::View3DInventor* view = dynamic_cast<Gui::View3DInventor*>(doc->getActiveView());
    assert(view);
    QWidget* node = dynamic_cast<QWidget*>(view);
    assert(node);
    return node;
}

SoQtViewer* getSoQtViewer()
{
    Gui::Document* doc = Gui::Application::Instance->getDocument("DDA");
    assert(doc);
    Gui::View3DInventor* view = dynamic_cast<Gui::View3DInventor*>(doc->getActiveView());
    assert(view);
    if (view) {
        Gui::View3DInventorViewer* viewer = view->getViewer();
        SoQtViewer* node = static_cast<SoQtViewer*>(viewer);
        assert(node);
        msg("SoqtViewer got.\n");
        return node;
    }
}

QMainWindow* getMainWindow()
{
    QWidgetList widgets =  QApplication::topLevelWidgets();
    QWidget* widget;
    for(int i=0 ; i<widgets.size() ; i++)
    {
        if(strcmp(widgets[i]->metaObject()->className(),"Gui::MainWindow")==0)
        {
            widget = widgets[i];
            return static_cast<QMainWindow*>(widget);
        } 
    }
}

// 
// void testFrameMaker()
// {
// 	FrameDataTaker dataTaker;
// 	assert(dataTaker.setFile("D:/DDAProject/data.dg"));
// 
//     msg("start to set frame maker.\n");
// 	FrameMaker frameMaker;
//     SoSeparator* root = getFreeCADRootNode();
//     assert(root);
// 	frameMaker.setRootSceneNode(root);
//     msg("start to reset frame maker.\n");
// 	frameMaker.reset(&dataTaker);
//     vector<int> schema = dataTaker.getSchema();
//     for(int i=0; i<1000; i++)
//     {
//         sleep(0.5);
//         msg("----------show one graph----------------.\n");
//         frameMaker.updateGraph(dataTaker.getNextGraph());
//     }
// // 
// }
// 
void testPostPlayer()
{
    DDAPostPlayer* player = new DDAPostPlayer;

    SoSeparator* root = getFreeCADRootNode();
    assert(root);
    player->setRootSceneNode(root);

    SoQtViewer* viewer = getSoQtViewer();
    assert(viewer);
    player->setSoQtViewer(viewer);

    player->show();
}
DDAPostPlayer* postPlayer = NULL;
QDockWidget* postPlayerDock = NULL;
void startPostPlayer()
{
    if(!postPlayer) 
    {
        postPlayer= new DDAPostPlayer(getMainWindow());
        postPlayer->setWindowFlags(Qt::Window|Qt::SubWindow|Qt::WindowTitleHint|Qt::CustomizeWindowHint);//|Qt::WindowStaysOnTopHint
//         if (!postPlayerDock)
//         {
//             postPlayerDock = new QDockWidget();
//             postPlayerDock->setAllowedAreas(Qt::AllDockWidgetAreas);
//             postPlayerDock->setFloating(false);
//             postPlayerDock->setFeatures(QDockWidget::DockWidgetFloatable |
//                 QDockWidget::DockWidgetMovable);
//         }
//         postPlayerDock->setWidget(postPlayer);
//         postPlayerDock->setFloating(true);
//         postPlayerDock->setMinimumWidth(500);
    }
    SoSeparator* root = getFreeCADRootNode();
    assert(root);
    postPlayer->setRootSceneNode(root);

    SoQtViewer* viewer = getSoQtViewer();
    assert(viewer);
    postPlayer->setSoQtViewer(viewer);

    postPlayer->show();
//    postPlayerDock->show();
}
void clearPostPlayer()
{
    if( postPlayer )
    {
        delete postPlayer;
        postPlayer = NULL;
    }
//     if(postPlayerDock)
//         postPlayerDock->hide();
}

DFCalculator* dfCalculator = NULL;
QDockWidget* calculatorDock = NULL;
void  startDFCalc()
{
    printf("try to start DF calculator.\n");
    printf("current project path: %s\n", currentProjectPath);
    if(!dfCalculator) 
        dfCalculator= new DFCalculator(getMainWindow());
    dfCalculator->setWindowFlags( Qt::Window |Qt::SubWindow| Qt::WindowTitleHint | Qt::CustomizeWindowHint);
//     if (!calculatorDock)
//     {
//         calculatorDock = new QDockWidget;
//         calculatorDock->setAllowedAreas(Qt::AllDockWidgetAreas);
//         calculatorDock->setFloating(false);
//         calculatorDock->setFeatures(QDockWidget::DockWidgetFloatable |
//             QDockWidget::DockWidgetMovable);
//         calculatorDock->setFloating(true);
//         calculatorDock->setMinimumWidth(500);
//     }
//     calculatorDock->setWidget(dfCalculator);

    SoSeparator* root = getFreeCADRootNode();
    assert(root);
    dfCalculator->setRootSceneNode(root);

    SoQtViewer* viewer = getSoQtViewer();
    assert(viewer);
    dfCalculator->setSoQtViewer(viewer);

	msg2File("Viewer got.");
    dfCalculator->initPlay();
	msg2File("DF Calculator initialized done.\n");
	printf("DF Calculator initialized done.\n");
//    calculatorDock->show();
    dfCalculator->show();
}
void clearCalculator()
{
    if( dfCalculator )
    {
        delete dfCalculator;
        dfCalculator = NULL;
    }
//     if(calculatorDock)
//         calculatorDock->hide();
}

void setCalculatorRealTime(int flag)
{
    if(!dfCalculator)
        dfCalculator = new DFCalculator;
    if(dfCalculator)
        dfCalculator->setRealTime(flag);
}

//===========================================================================
// CmdDFCalc is the command to do DDA analysis
//===========================================================================
DEF_STD_CMD_A(CmdDFCalc);

CmdDFCalc::CmdDFCalc()
:Command("DDA_DFCalc")
{
    sAppModule    = "DDA";
    sGroup        = QT_TR_NOOP("DDA");
    sMenuText     = QT_TR_NOOP("Hello");
    sToolTipText  = QT_TR_NOOP("DFCalculation");
    sWhatsThis    = QT_TR_NOOP("DFCalculation");
    sStatusTip    = QT_TR_NOOP("DFCalculation");
    sPixmap       = "Test1";
}



void CmdDFCalc::activated(int iMsg)
{
    saveTime();
    msg("start to df calculation.\n");

    startDFCalc();

    Base::Console().Message("Hello, World!\n");
}

bool CmdDFCalc::isActive()
{
    return true;
}

//===========================================================================
// CmdDDATest THIS IS JUST A TEST COMMAND
//===========================================================================
DEF_STD_CMD(CmdDDATest);

CmdDDATest::CmdDDATest()
:Command("DDA_Test")
{
    sAppModule    = "DDA";
    sGroup        = QT_TR_NOOP("DDA");
    sMenuText     = QT_TR_NOOP("Hello");
    sToolTipText  = QT_TR_NOOP("DDA Test function");
    sWhatsThis    = QT_TR_NOOP("DDA Test function");
    sStatusTip    = QT_TR_NOOP("DDA Test function");
    sPixmap       = "Test1";
    sAccel        = "CTRL+H";
}



void CmdDDATest::activated(int iMsg)
{
//     assert(SoDB::isMultiThread());
// 	testFrameDataTaker();
// 	msg("one graph read done.\n");
//     testFread();

	saveTime();
    msg("start to read graph.\n");

//     testPostPlayer();
    startPostPlayer();
//    startDFCalc();

    Base::Console().Message("Hello, World!\n");
}



void CreateDDACommands(void)
{
    Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
    rcCmdMgr.addCommand(new CmdDFCalc());
    rcCmdMgr.addCommand(new CmdDDATest());
}
